//
// Created by root on 20-2-17.
//

#include <android/log.h>
#include <dlfcn.h>
#include "art_method.h"
#include "cxx_helper.h"
#include "modifiers.h"
#include "dlfcn_nougat.h"

static bool sReady= false;

static size_t sMethodSize=INT32_MAX;

static offset_t sAccessFlagsOffset=INT32_MAX;

ArtMethod::ArtMethod(jmethodID method) {
    if(!sReady)
        return;
    mMethod=method;
}

void ArtMethod::SystemReady() {
    sReady=true;
}

void ArtMethod::SetAccessFlags(u4 access_flags) {
    offset_t offset=GetAccessFlagsOffset();
    AssignOffset(mMethod,offset,access_flags);
}

u4 ArtMethod::GetAccessFlags() {
    offset_t offset=GetAccessFlagsOffset();
    return MemberOf<u4>(mMethod,offset);
}

void ArtMethod::RemoveAccessFlags(u4 af_bit) {
    SetAccessFlags(GetAccessFlags() & ~af_bit);
}

bool ArtMethod::HasAccessFlags(u4 af_bit) {
    return (af_bit & GetAccessFlags()) != 0;
}

void ArtMethod::SetAccessFlagsOffset(offset_t offset) {
    sAccessFlagsOffset=offset;
}

offset_t ArtMethod::GetAccessFlagsOffset() {
    return sAccessFlagsOffset;
}

void ArtMethod::AddAccessFlags(u4 af_bit) {
        SetAccessFlags(GetAccessFlags() | af_bit);
}

void ArtMethod::SetMethodSize(size_t size) {
    sMethodSize=size;
}

size_t ArtMethod::GetMethodSize() {
    return sMethodSize;
}

void* find_new_local_ref(){
    static ptr_t symbol= nullptr;
    if(symbol)
        return symbol;
    std::string lib_path=get_system_lib_dir();
    lib_path.append("libart.so");
    ptr_t handle=fake_dlopen(lib_path.c_str(),RTLD_NOW);
    symbol= fake_dlsym(handle,"_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE");
    __android_log_print(ANDROID_LOG_DEBUG,"Symbol","new_local_ref:%p\n",symbol);
    return symbol;
}

jclass ArtMethod::GetDeclaringClass(JNIEnv *env) {
    //N（7.0）及之后的版本加了一个GcRoot，需要继续根据偏移确定
    void* mirror_decl_class= MemberOf<ptr_t>(mMethod,0);
    void* symbol=find_new_local_ref();
    if(!symbol)
        return nullptr;
    jobject (*JniEnvExt_NewLocalRef)(JNIEnv *jnienv_ext_this, ptr_t art_object);
    JniEnvExt_NewLocalRef= reinterpret_cast<jobject (*)(JNIEnv *, ptr_t)>(symbol);
    jobject decl_class= JniEnvExt_NewLocalRef(env,mirror_decl_class);
    return (jclass)decl_class;
}

jobject ArtMethod::ToReflectedMethod(JNIEnv *env) {
    using namespace whale::art;
    bool is_static=HasAccessFlags(kAccStatic);
    jclass decl_class=GetDeclaringClass(env);
    return env->ToReflectedMethod(decl_class,mMethod,is_static);
}


